package com.zzz.gp.utils;


import com.zzz.gp.bean.ModeConf;
import com.zzz.gp.bean.MyZkSerializer;
import com.zzz.gp.bean.ZKClientConf;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @description: ZKClient 实现配置中心案例
 * @author: ZZZ
 * @time: 2021/3/21 17:09
 */
//@Component
public class ZkClientLimit {
    @Value("${zk.url}")
    private String connectString;
    @Value("${zk.flag}")
    private boolean zkFlag ;

    //@Autowired
    private ZKClientConf conf;

    private ZkClient zkClient;

    @PreDestroy
    private void close() {
        zkClient.close();
    }

    @PostConstruct
    private ZkClient init() {
        if (zkFlag) {
            synchronized (ZkClientLimit.class) {
                zkClient = new ZkClient(connectString);
                zkClient.setZkSerializer(new MyZkSerializer());



                //初始化interval
                Object o = zkClient.readData(conf.getConfPath());
                conf.setInterval(o.toString());
                //监听节点 /zzz interval
                zkClient.subscribeDataChanges(conf.getConfPath(), new IZkDataListener() {
                    @Override
                    public void handleDataChange(String s, Object o) throws Exception {
                        System.out.println("节点发送变化  " + s + "  " + o);
                        conf.setInterval(o.toString());
                    }

                    @Override
                    public void handleDataDeleted(String s) throws Exception {
                        System.out.println("节点删除  " + s);
                        conf.getConfMode().clear();
                        conf.setInterval("5");
                    }
                });

                //监听子节点  /zzz/A  10
                List<String> childList = zkClient.subscribeChildChanges(conf.getConfPath(), new IZkChildListener() {
                    public void handleChildChange(String s, List<String> list) throws Exception {
                        System.out.println(conf.getConfPath() + "子节点发生变化");
                        ModeChanges(s, list);
                    }
                });
                //子节点点初始化
                ModeChanges(conf.getConfPath(), childList);
            }
        }
        return zkClient;
    }

    //监听子节点
    public void ModeChanges(String confPath, List<String> list) {
        System.out.println("+++++++++++++++++++++++++++");
        for (String child : list) {
            //map中没有说明是新增的,需要把新增的放入缓存中去
            if (!conf.getConfMode().containsKey(child)) {

                //监听 /zzz/A
                Object modeValue = zkClient.readData(conf.getConfPath() + "/" + child);
                saveMode(child, modeValue.toString(), true);

                zkClient.subscribeDataChanges(confPath + "/" + child, new IZkDataListener() {
                    @Override
                    public void handleDataChange(String s, Object o) throws Exception {
                        System.out.println(s + "节点发送变化：" + " 数据：" + o);
                        // /zzz/A  A
                        int n = s.lastIndexOf("/");
                        saveMode(s.substring(n + 1), o.toString(), false);
                    }

                    @Override
                    public void handleDataDeleted(String s) throws Exception {
                        System.out.println("节点发送变化：" + s);
                        // /zzz/A
                        conf.getConfMode().remove(child);
                    }
                });

                //监听 /zzz/A/A_1
                String modePath = conf.getConfPath() + "/" + child;
                List<String> userList = zkClient.subscribeChildChanges(modePath, new IZkChildListener() {
                    @Override
                    public void handleChildChange(String s, List<String> list) throws Exception {
                        updateUerMode(child, list);
                        saveUser(s, list);
                    }
                });
                saveUser(modePath, userList);
            }
        }

    }

    //保存Mode
    public void saveMode(String modeKey, String modeValue, boolean initFlag) {
        ModeConf modeConf = conf.getConfMode().get(modeKey);
        if (modeConf == null) {
            modeConf = new ModeConf();

        }
        modeConf.setMode(modeKey);
        modeConf.setModeValue(modeValue);
        conf.getConfMode().put(modeKey, modeConf);

        if (initFlag) {
            List<String> newUser = zkClient.getChildren(conf.getConfPath() + "/" + modeKey);
            updateUerMode(modeKey, newUser);
        }
    }

    //更新 userMode
    public void updateUerMode(String modeKey, List<String> newUser) {
        ModeConf modeConf = conf.getConfMode().get(modeKey);
        List<String> oldUser = modeConf.getUser();
        modeConf.setUser(newUser);

        ConcurrentHashMap<String, String> userMode = conf.getUserMode();
        if (oldUser != null) {
            for (String s : oldUser) {
                userMode.remove(s);

            }
        }
        if (newUser != null) {
            for (String s : newUser) {
                userMode.put(s, modeKey);
            }
        }

    }

    public void saveUser(String modePath, List<String> userList) {

        ConcurrentHashMap<String, List<String>> userType = conf.getUserType();
        for (String userKey : userList) {
            if (!userType.contains(userKey)) {

                Object o = zkClient.readData(modePath + "/" + userKey);
                saveUserType(modePath + "/" + userKey, o.toString());

                zkClient.subscribeDataChanges(modePath + "/" + userKey, new IZkDataListener() {
                    @Override
                    public void handleDataChange(String s, Object o) throws Exception {
                        saveUserType(s, o.toString());
                    }

                    @Override
                    public void handleDataDeleted(String s) throws Exception {
                        int n = s.lastIndexOf("/");
                        conf.getUserType().remove(s.substring(n + 1));

                    }
                });
            }
        }
    }

    public void saveUserType(String userTypePath, String userTypeValue) {
        int n = userTypePath.lastIndexOf("/");

        String[] userTypeValueString = userTypeValue.split(",");
        List<String> userTypeValueList = Arrays.asList(userTypeValueString);

        conf.getUserType().put(userTypePath.substring(n + 1), userTypeValueList);

    }

}